package com.ipan.jfinal.simpleApi;

import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ipan.kits.id.IdUtil;
import com.ipan.kits.number.RandomUtil;
import com.ipan.kits.security.MD5;
import com.ipan.kits.time.DateFormatUtil;

/**
 * 头部校验字段定义
 * 
 * userid在HTTP BODY里面，需要根据userid获取appkey，然后生成签名做校验；
 * 需要修改HTTP HEAD键值，参考SimpleApiManager.setAuthHeadKey或setAuthHeadHead；
 * 
 * @author iPan
 * @date 2022-06-29
 */
public class AuthHead implements java.io.Serializable {
	private static Logger LOG = LoggerFactory.getLogger(AuthHead.class);
	private static final long serialVersionUID = 1L;
	private static final String HEAD_PATTERN = "^(AppId|UserId|Timestamp|Nonce|Signature)=\"([\\w\\-\\+/=]+)\"(,(AppId|UserId|Timestamp|Nonce|Signature)=\"([\\w\\-\\+/=]+)\")+$";
	static String HEAD = "OPEN-BODY-SIG";
	static String KEY = "Authorization";
	
	public static String getHead() {
		return HEAD;
	}
	public static String getKey() {
		return KEY;
	}

	/** APPID（长度32位） */
	private String appId = null;
	/** USERID（长度32位） */
	private String userId = null;
	/** 时间截（格式：yyyyMMddHHmmss） */
	private String timestamp = null;
	/** 随机数（长度不超过128位） */
	private String nonce = null;
	/** 签名 */
	private String signature = null;
	
	public AuthHead() {}
	
	public AuthHead(String appId, String userId, String timestamp, String nonce, String signature) {
		this.appId = appId;
		this.userId = userId;
		this.timestamp = timestamp;
		this.nonce = nonce;
		this.signature = signature;
	}
	public String getAppId() {
		return appId;
	}
	public void setAppId(String appId) {
		this.appId = appId;
	}
	public String getUserId() {
		return userId;
	}
	public void setUserId(String userId) {
		this.userId = userId;
	}
	public String getTimestamp() {
		return timestamp;
	}
	public void setTimestamp(String timestamp) {
		this.timestamp = timestamp;
	}
	public String getNonce() {
		return nonce;
	}
	public void setNonce(String nonce) {
		this.nonce = nonce;
	}
	public String getSignature() {
		return signature;
	}
	public void setSignature(String signature) {
		this.signature = signature;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((appId == null) ? 0 : appId.hashCode());
		result = prime * result + ((nonce == null) ? 0 : nonce.hashCode());
		result = prime * result + ((signature == null) ? 0 : signature.hashCode());
		result = prime * result + ((timestamp == null) ? 0 : timestamp.hashCode());
		result = prime * result + ((userId == null) ? 0 : userId.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		AuthHead other = (AuthHead) obj;
		if (appId == null) {
			if (other.appId != null)
				return false;
		} else if (!appId.equals(other.appId))
			return false;
		if (nonce == null) {
			if (other.nonce != null)
				return false;
		} else if (!nonce.equals(other.nonce))
			return false;
		if (signature == null) {
			if (other.signature != null)
				return false;
		} else if (!signature.equals(other.signature))
			return false;
		if (timestamp == null) {
			if (other.timestamp != null)
				return false;
		} else if (!timestamp.equals(other.timestamp))
			return false;
		if (userId == null) {
			if (other.userId != null)
				return false;
		} else if (!userId.equals(other.userId))
			return false;
		return true;
	}
	
	@Override
	public String toString() {
		StringBuilder buf = new StringBuilder();
		buf.append(getKey()).append(":")
			.append(getHead()).append(" ")
			.append("AppId=\"").append(appId).append("\",")
			.append("UserId=\"").append(userId).append("\",")
			.append("Timestamp=\"").append(timestamp).append("\",")
			.append("Nonce=\"").append(nonce).append("\",")
			.append("Signature=\"").append(signature).append("\"");
		return buf.toString();
	}
	
	public String toHeadValue() {
		StringBuilder buf = new StringBuilder();
		buf	.append(getHead()).append(" ")
			.append("AppId=\"").append(appId).append("\",")
			.append("UserId=\"").append(userId).append("\",")
			.append("Timestamp=\"").append(timestamp).append("\",")
			.append("Nonce=\"").append(nonce).append("\",")
			.append("Signature=\"").append(signature).append("\"");
		return buf.toString();
	}
	
	/**
	 * 解析头部
	 * 
	 * 格式：XAuth（可自定义）: OPEN-BODY-SIG AppId="AppId", Timestamp="时间戳", Nonce="随机数", Signature="签名"
	 * 
	 * @param headAuth http头部
	 * @return 解析对象
	 */
	public static AuthHead parseHead(String headAuth) {
		Validate.notBlank(headAuth, "http token不能为空");
		if (!headAuth.startsWith(AuthHead.HEAD)) {
			throw new IllegalArgumentException("http token格式不正确");
		}
		
		String str = StringUtils.substringAfter(headAuth, AuthHead.HEAD).replaceAll("[ \\s]", "");
		if(!Pattern.matches(HEAD_PATTERN, str)) {
			throw new IllegalArgumentException("http token格式不正确");
		}
		
		AuthHead obj = null;
		String appId = null, userId = null, timestamp = null, nonce = null, signature = null;
		try {
			String[] arr = str.split(",");
			Map<String, String> kv = new HashMap<String, String>();
			for (String item : arr) {
				int index = item.indexOf("=");
				String[] kvItem = new String[] {item.substring(0, index), item.substring(index + 1)};
				kv.put(kvItem[0], kvItem[1].replace("\"", ""));
			}
			appId = kv.get("AppId");
			userId = kv.get("UserId");
			timestamp = kv.get("Timestamp");
			nonce = kv.get("Nonce");
			signature = kv.get("Signature");
		} catch (Exception e) {
			LOG.error("http token格式不正确", e);
			throw new IllegalArgumentException("http token格式不正确");
		}
		if (StringUtils.isBlank(appId) || StringUtils.isBlank(userId) || StringUtils.isBlank(timestamp) 
				|| StringUtils.isBlank(nonce) || StringUtils.isBlank(signature)
				|| userId.length() != 32) {
			throw new IllegalArgumentException("http token格式不正确");
		}
		try {
			DateFormatUtil.parseDate("yyyyMMddHHmmss", timestamp);
		} catch (ParseException e) {
			throw new IllegalArgumentException("时间Timestamp格式不正确");
		}
		if (!StringUtils.isNumeric(nonce) || nonce.length() > 128) {
			throw new IllegalArgumentException("随机数Nonce格式不正确");
		}
		obj = new AuthHead();
		obj.setAppId(appId);
		obj.setUserId(userId);
		obj.setTimestamp(timestamp);
		obj.setNonce(nonce);
		obj.setSignature(signature);
		return obj;
	}
	
	/**
	 * 创建Timestamp（格式：yyyyMMddHHmmss）
	 */
	public static String createTimestamp() {
		return DateFormatUtil.formatDate("yyyyMMddHHmmss", new Date());
	}
	
	/**
	 * 创建随机数nonce（不超过128位）
	 */
	public static String createNonce() {
		return RandomUtil.nextLong(100000000, 999999999) + "";
	}
	
	/**
	 * 创建唯一ID（客户流水号，不超过32位。）
	 */
	public static String createId() {
		return MD5.digestHex(IdUtil.fastUUID().toString());
	}

}
